#include "stdafx.h"
//-------------------------------------------------------------------------------------------------
//ProcParams.cpp  - Collection of Parameters for Image Processing Steps       
//-------------------------------------------------------------------------------------------------
//FreeBSD License
//Copyright 2012 Will Stott All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list of
//      conditions and the following disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this list
//      of conditions and the following disclaimer in the documentation and/or other materials
//      provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Will Stott ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Will Stott OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Will Stott.
//
//----Authors--------------------------------------------------------------------------------------
//created by: will.stott@ucl.ac.uk Feb 2012
//
//----Comments-------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------
#include "tinyxml.h"
#include "tinyxmlHelper.h"
#include "ImageExptLib.h"

#include "ImageProcStep.h"
#include "ProcParams.h"

const char * const ProcParams::attribParamCnt = "Count";
const char * const ProcParams::ParamNameImageFile = "ImageFile";

ProcParams::ProcParams(void) :
	_attribParamCnt(ProcParams::NotFound),
	_error(true)
{
}

ProcParams::ProcParams(const ProcParams *params)
{
	if (params != '\0')
	{
		_error = params->_error;
		_attribParamCnt = params->_attribParamCnt;

		int cnt = static_cast<int>(params->_Params.size());
		for (int x = 0; x < cnt; x++)
		{
			ProcParam *pSrcParam = '\0';
			if ( (pSrcParam = params->_Params[x]) == '\0')
				ImageExptLib::LogMsg("ProcParams::ProcParams(copy ctor)", "ERROR: source param %d is null", x);
			else
			{
				ProcParam *pDestParam = '\0';
				if ((pDestParam = ProcParam::CreateProcParam(pSrcParam)) == '\0')
					ImageExptLib::LogMsg("ProcParams::ProcParams(copy ctor)", "ERROR: unable to copy param %d - %s", x, pSrcParam->GetName());
				else
				{
					if (AddParam(pDestParam) == false)
					{
						delete pDestParam;
						ImageExptLib::LogMsg("ProcParams::ProcParams(copy ctor)", "ERROR: unable to add param %d - %s", x, pSrcParam->GetName());
					}
				}
			}
		}
	}
//	Validate();
}

ProcParams::ProcParams(TiXmlElement *stepXml, const char *paramIOName):
	_attribParamCnt(0),
	_error(true)
{
	if ((stepXml == '\0') || (paramIOName == '\0'))
		ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: stepXml is %s, paramIOName is %s", ((stepXml == '\0') ? "null" : "not null"), ((paramIOName == '\0') ? "null" : "not null"));
	else
	{
		std::string val(stepXml->Value());
		if ( val != ImageProcStep::xmlProcStep) 
			ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: input param is <%s> rather than <%s>", val.c_str(), ImageProcStep::xmlProcStep);
		else
		{
			int StepCnt = ImageProcStep::InvalidStepNum;
			if ( stepXml->Attribute(ImageProcStep::attribStepNum, &StepCnt) == '\0')
				ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: <%s> does not contain attrib %s ", val.c_str(), ImageProcStep::attribStepNum);
			else
			{
				TiXmlElement *ioXml = '\0';
				if( (ioXml = TinyXmlHelper::FindChildXmlElement(stepXml, paramIOName)) == '\0')
					ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: step %d, <%s> does not contain child <%s> ", StepCnt, val.c_str(), paramIOName);
				else
				{
					if ( ioXml->Attribute(ProcParams::attribParamCnt, &_attribParamCnt) == '\0')
						ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: step %d, attribute %s not found in <%s>", StepCnt, ProcParams::attribParamCnt, paramIOName);
					else
					{
						int FoundParams = 0;
						ProcParam *param = '\0';

						TiXmlElement *paramXml = '\0';
						for( paramXml = TinyXmlHelper::FindChildXmlElement(ioXml, IPluginICProcStepsParamXmlProcParam); paramXml != '\0'; paramXml = paramXml->NextSiblingElement() )
						{
							if ((param = CreateParam(StepCnt, paramIOName, paramXml)) == '\0')
								ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: step %d, param %d from <%s> could not be created", StepCnt, FoundParams, paramIOName);
							else
							{
								if (AddParam(param) == false)
								{
									ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: step %d, param %d from <%s> could not be added to ProcParams", StepCnt, FoundParams, paramIOName);
									delete param;
									break;
								}
								else
								{
									FoundParams++;
								}
							}
						}
						if (FoundParams != _attribParamCnt)
							ImageExptLib::LogMsg("ProcParams::ProcParams", "ERROR: step %d, expected %d <%s> in <%s> but found only %d", StepCnt, _attribParamCnt, IPluginICProcStepsParamXmlProcParam, paramIOName, FoundParams);
					}
				}
			}
		}
	}
}


ProcParams::~ProcParams(void)
{
	ClearParams();
}

bool ProcParams::ClearParams()
{
	bool rc = false;

	size_t cnt = _Params.size();
	if (cnt > 0 )
	{
		for (size_t x = 0; x < cnt; x++)
			delete  _Params[x];
		_Params.clear();
		rc = true;
	}
	_error = true;
	return rc;
}

bool	ProcParams::IsAnalysisSet()
{
	return false;	//only ProcParamsOutputs should contain a set of output params with Score
}

bool	ProcParams::IsValid()
{
	return (_error == true) ? false : true;
}

bool	ProcParams::Validate()
{
	bool rc = false;

	size_t cnt = _Params.size();
	if (cnt < 1 )
		ImageExptLib::LogMsg("ProcParams::Validate", "ERROR: No Params found");
	else
	{
		if ((_attribParamCnt != ProcParams::NotFound) && (_attribParamCnt != cnt))
			ImageExptLib::LogMsg("ProcParams::Validate", "ERROR: Param cnt=%d does not match params in Xml=%d", cnt, _attribParamCnt);
		else
		{
			rc = true;
			for (size_t x = 0; x < cnt; x++)
			{
				if (GetParamPrivate(x) == '\0')	//each param in list must have index in range 0 to _Params.size() - assume they are all valid as AddParam() calls IsValid()
				{
					ImageExptLib::LogMsg("ProcParams::Validate", "ERROR: Param not found for pos=%d", x);
					rc = false;
					break;
				}
			}
		}
		if ( rc == true )
			_error = false;
	}
	return rc;	//implementation in ProcParamsOutputs results true only if the param set contains result
}

bool	ProcParams::AddParam(ProcParam *param)
{
	bool rc = false;

	if (param == '\0')
		ImageExptLib::LogMsg("ProcParams::AddParam", "ERROR: Input param is null");
	else
	{
		if ( param->IsValid() == false)
			ImageExptLib::LogMsg("ProcParams::AddParam", "ERROR: Input Param (%s) is invalid", param->GetName());
		else
		{
			int	index = IPluginICProcStepsParam::Invalid;
			if ( (index = param->GetIndex()) == IPluginICProcStepsParam::Invalid)
				ImageExptLib::LogMsg("ProcParams::AddParam", "ERROR: Input param has invalid index");
			else
			{
				if ( IsAlreadyPresent(param, index) == true)	//checks param is not null and is valid
					ImageExptLib::LogMsg("ProcParams::AddParam", "ERROR: Input Param (%s) is already present", param->GetName());
				else
				{
					_Params.push_back(param);
					_error = true;		//must eventually validate this collection of parameters to check that they form a valid set; i.e. no missing indexs, etc
					rc = true;
				}
			}
		}
	}
	return rc;
}

ProcParam *ProcParams::GetParamByPosition(int pos) 
{ 
	ProcParam *rc = '\0';

	if (IsValid() == false)
		ImageExptLib::LogMsg("ProcParams::GetParamByPosition", "ERROR: Params not validated");
	else
	{
		int cnt = (int)_Params.size();
		if ((pos > (cnt-1)) || (pos < 0))
			ImageExptLib::LogMsg("ProcParams::GetParamByPosition", "ERROR: Input pos=%d not valid, count=%d", pos, cnt);
		else
			rc = _Params[pos];
	}
	return rc; 
}

int	ProcParams::GetParamCount() 
{ 
	int rc = ProcParams::NotFound;

	if (IsValid() == false)
		ImageExptLib::LogMsg("ProcParams::GetParamCount", "ERROR: Params not validated");
	else
	{
		rc = static_cast<int>(_Params.size()); 
	}
	return rc;
}

ProcParam *	ProcParams::GetParam(const char *Name)
{
	ProcParam *rc = '\0';

	if (IsValid() == false)
		ImageExptLib::LogMsg("ProcParams::GetParam(name)", "ERROR: Params not validated");
	else
	{
		int index = IPluginICProcStepsParam::Invalid;
		if ( (index = GetPosition(Name)) != IPluginICProcStepsParam::Invalid)
			rc = _Params[index];
	}

	return rc;
}

ProcParam *	ProcParams::GetParam(int Index)
{
	ProcParam *rc = '\0';

	if (IsValid() == false)
		ImageExptLib::LogMsg("ProcParams::GetParam(index)", "ERROR: Params not validated");
	else
		rc = GetParamPrivate(Index);

	return rc;
}

int	ProcParams::GetIndex(const char *Name)
{
	int rc = ProcParams::NotFound;

	if (IsValid() == false)
		ImageExptLib::LogMsg("ProcParams::GetParam(name)", "ERROR: Params not validated");
	else
	{
		if (Name == '\0')
			ImageExptLib::LogMsg("ProcParams::GetParam(name)", "ERROR: Input param is null");
		else
		{
			std::string name(Name);
			size_t cnt = _Params.size();
			for (size_t x = 0; x < cnt; x++)
			{
				if (name == _Params[x]->GetName())
				{
					rc = _Params[x]->GetIndex();
					break;
				}
			}
		}
	}
	return rc;
}

//-------------------------------------------------------------------------------------------------
//			PRIVATE
//-------------------------------------------------------------------------------------------------

int	ProcParams::GetPosition(const char *Name)
{
	int rc = ProcParams::NotFound;

	if (Name == '\0')
		ImageExptLib::LogMsg("ProcParams::GetPosition", "ERROR: Input param is null");
	else
	{
		std::string name(Name);
		size_t cnt = _Params.size();
		if (cnt > 0 )
		{
			for (size_t x = 0; x < cnt; x++)
			{
				if (name == _Params[x]->GetName())
				{
					rc = x;
					break;
				}
			}
		}
	}
	return rc;
}

ProcParam *	ProcParams::GetParamPrivate(int Index)
{
	ProcParam *rc = '\0';

	size_t cnt = _Params.size();
	for (size_t x = 0; x < cnt; x++)
	{
		if ( _Params[x]->GetIndex() == Index)
		{
			rc = _Params[x];
			break;
		}
	}
	return rc;
}

bool	ProcParams::IsAlreadyPresent(ProcParam *param, int index)
{
	bool rc = false;			//assume param != null and (param->getIndex() != ProcParams::NotFound) && (param->getIndex() == index)

	size_t cnt = _Params.size();
	if (cnt > 0 )
	{		//first check index is unique
		for (size_t x = 0; x < cnt; x++)
		{
			if (index == _Params[x]->GetIndex())
			{
				rc = true;
				break;
			}
		}
		if (rc == false )
		{	//now check name is unique
			std::string name(param->GetName());
			for (size_t x = 0; x < cnt; x++)
			{
				if (name == _Params[x]->GetName())
				{
					rc = true;
					break;
				}
			}
		}
	}
	return rc;
}

ProcParam *ProcParams::CreateParam(int StepNum, const char *ParamIOName, TiXmlElement *paramXml)
{
	ProcParam *rc = '\0';

	int Index = ProcParams::NotFound;
	paramXml->Attribute(IPluginICProcStepsParamAttribIndex, &Index); 

	std::string direction(ParamIOName);
	IPluginICProcStepsParam::Direction dir =  (direction == ProcParamsInputs::xmlInputs ) ? IPluginICProcStepsParam::input : IPluginICProcStepsParam::output;
	
	rc = ProcParam::CreateProcParam(paramXml->Attribute(IPluginICProcStepsParamAttribType), 
		paramXml->Attribute(IPluginICProcStepsParamAttribName), 
		Index, 
		dir,
		paramXml->GetText());

	return rc;
}
//-------------------------------------------------------------------------------------------------
//			E N D   O F   F I L E
//-------------------------------------------------------------------------------------------------
